package com.gopay.bis.manager.bank.ebank;

import com.gopay.bis.dao.corp.CustCorpInfoDao;
import com.gopay.bis.manager.bank.BankOrderManager;
import com.gopay.bis.manager.bank.NuccSerialManager;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BankOfAffiliationConstants;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.NuccConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseHeaderMessage;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseMessage;
import com.gopay.common.domain.bank.nucc.common.query.req.NuccQueryBodyOriTrxinf;
import com.gopay.common.domain.bank.nucc.common.query.req.NuccQueryBodyReq;
import com.gopay.common.domain.bank.nucc.common.query.res.NuccQueryRes;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyOriTrxinf;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyPyeeinf;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyPyerinf;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyReq;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyResfdinf;
import com.gopay.common.domain.bank.nucc.common.refund.req.NuccRefundBodyTrxinf;
import com.gopay.common.domain.bank.nucc.common.refund.res.NuccRefundRes;
import com.gopay.common.domain.bank.nucc.ebank.pay.end.NuccEbankEndRes;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyOrdrinf;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyPyeeinf;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyPyerinf;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyReq;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyResfdinf;
import com.gopay.common.domain.bank.nucc.ebank.pay.req.NuccEbankBodyTrxinf;
import com.gopay.common.domain.bank.nucc.ebank.pay.res.NuccEbankRes;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.pg.PgGenOrderTransDtl;
import com.gopay.common.exception.GopayException;
import com.gopay.common.order.dao.PgGeneralOrderTransDtlDAO;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.BankManagerRemoteService;
import com.gopay.remote.bank.businesses.NuccCommonService;
import com.gopay.remote.bank.businesses.NuccEbankService;
import com.ibm.icu.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

/**
 * 网联网关支付-对私
 * @NuccB2cManager.java
 * @author zhoutong
 * @2018-1-16 下午1:48:47 www.gopay.com.cn Inc.All rights reserved.
 */
public class NuccB2cManager implements BankManagerRemoteService {

	private static Logger logger = LoggerFactory.getLogger(NuccB2cManager.class);

	@Resource(name = "nuccConfig")
	private Map<String, String> nuccConfig;
	
	@Resource(name = "cpsGeneralMainOrderQueryManager")
	private CpsGeneralMainOrderQueryManager mainOrderQuery;

	@Resource(name = "custCorpInfoDao")
	private CustCorpInfoDao custCorpInfoDao;

	@Resource(name = "commonPgGeneralOrderTransDtlDAO")
	private PgGeneralOrderTransDtlDAO commonPgGeneralOrderTransDtlDAO;

	@Resource(name = "nuccSerialManager")
	private NuccSerialManager nuccSerialManager;

	@Resource(name = "nuccGwServiceClient")
	private NuccEbankService nuccGwServiceClient;

	@Resource(name = "nuccCommonServiceClient")
	private NuccCommonService nuccCommonServiceClient;

	@Resource(name = "bankOrderManager")
	private BankOrderManager bankOrderManager;
	
	@Override
	public Object sign(BaseMessage base) throws GopayException {
		NuccBaseMessage message = this.buildPayment(base);
		logger.info("nucc b2c manager payment send message: " + ToStringBuilder.reflectionToString(message));
		NuccEbankRes res = (NuccEbankRes) nuccGwServiceClient.payment(message);
		res.setOutStlmCd(BankConstants.BANK_LOGO_NUCCPAY);
		logger.info("nucc b2c manager payment return message: " + ToStringBuilder.reflectionToString(res));
		return res;
	}
	/**
	 * 构建网关支付申请报文
	 * @param base
	 * @return
	 * @author zhoutong
	 */
	public NuccBaseMessage buildPayment(BaseMessage base) throws GopayException {
		NuccBaseMessage message = new NuccBaseMessage();
		BeanUtils.copyProperties(base, message);
		NuccBaseHeaderMessage header = new NuccBaseHeaderMessage();
		NuccEbankBodyReq body = new NuccEbankBodyReq();
		try{
			//通过订单号获取主订单信息
			CpsGenMainOrder mainOrder = mainOrderQuery.get(base.getOrderId());
			//获取商户信息
			CustCorpInfo custCorpInfo = custCorpInfoDao.getByCustId(mainOrder.getMerId());
			//拼接订单详情
			StringBuilder orderDescSb = new StringBuilder();
			if (null != custCorpInfo) {
				orderDescSb.append("1|1|").append(custCorpInfo.getCorpName())
						.append("%").append(mainOrder.getMerId()).append("%")
						.append(custCorpInfo.getCorpType()).append("%")
						.append("").append("%").append("").append("%")
						.append(custCorpInfo.getGopayMccCode()).append("%");
			}else{
				orderDescSb.append("||").append("").append("%").append("").append("%")
						.append("").append("%").append("").append("%").append("").append("%")
						.append("").append("%");
			}
			//获取交易流水信息
			String hql = " from PgGenOrderTransDtl where transDtlSq = :transDtlSq";
			Map paramMap = new HashMap();
			paramMap.put("transDtlSq",mainOrder.getTransDtlSq());
			List<PgGenOrderTransDtl> transDtls = commonPgGeneralOrderTransDtlDAO.findByHql(hql, paramMap);
			if (null != transDtls && transDtls.size()>0) {
				PgGenOrderTransDtl transDtl = transDtls.get(0);
				orderDescSb.append("1#1#").append(transDtl.getGoodsName())
						.append("^").append(transDtl.getMerTxnAmt())
						.append("^").append("|");
			}else{
				orderDescSb.append("##").append("").append("^").append("").append("^").append("|");
			}
			header.setSndDt(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
			//报文类型代码
			header.setMsgTp(nuccConfig.get("NUCC.GW.PAY.MSGTP"));
			//发起方所属机构标示
			header.setIssrId(nuccConfig.get("GOPAY.ISSRID"));
			//报文方向  11-支付机构到平台
			header.setDrctn(nuccConfig.get("NUCC.DRCTN.TONUCC"));
			//签名证书序列号
			header.setSignSN(nuccConfig.get("NUCC.GW.SIGNSN"));

			//付款方信息
			NuccEbankBodyPyerinf pyerInf = new NuccEbankBodyPyerinf();
			//付款方账户所属机构标示
			pyerInf.setPyerAcctIssrId(BankOfAffiliationConstants.getAffiliation(base.getBank()));
			pyerInf.setCbFlg(NuccConstants.NUCC_GW_CBFLG_PERSON);//网关支付类型
			pyerInf.setLmtAcctTp(NuccConstants.NUCC_LMTACCTTP_MIX);//限定账户类型
			pyerInf.setPyerAcctTp("00");  //付款方账户类型写死 ，待改造

			//收款方信息
			NuccEbankBodyPyeeinf pyeeInf = new NuccEbankBodyPyeeinf();
			//收款方账户所属机构标示
			pyeeInf.setPyeeAcctIssrId(nuccConfig.get("GOPAY.ISSRID"));
			//收款方账户
			pyeeInf.setPyeeAcctId(mainOrder.getMainRecvAcct());
			//收款方名称
			pyeeInf.setPyeeNm(custCorpInfo.getCorpName());
			//收款方账户类型
			pyeeInf.setPyeeAcctTp("04");

			//备付金信息
			NuccEbankBodyResfdinf resfdInf = new NuccEbankBodyResfdinf();
			String[] aInfo = nuccSerialManager.getAccountInfo(base.getBank());
			//支付机构备付金账户
			resfdInf.setInstgAcctId(aInfo[0]);
			//备付金账户所属机构标示
			resfdInf.setResfdAcctIssrId(aInfo[1]);
			
/*			//支付机构备付金账户
			resfdInf.setInstgAcctId(nuccConfig.get("NUCC.GWB2C.GOPAY.INSTG.ACCT.ID"));
			//备付金账户所属机构标示
			resfdInf.setResfdAcctIssrId(nuccConfig.get("NUCC.GWB2C.GOPAY.RESFD.ACCT.ISSRID"));
*/
			//交易信息
			NuccEbankBodyTrxinf trxInf = new NuccEbankBodyTrxinf();
			trxInf.setTrxDtTm(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
			// 金额，以分为单位
			String amount = "CNY"+amountFormat(base.getAmount().toString());
			trxInf.setTrxAmt(amount);
			//交易类别
			trxInf.setTrxCtgy(nuccConfig.get("NUCC.GW.PAY.TRXCTGY"));
			//网关支付流水号
			trxInf.setGwTrxId(base.getBankOrderId());
			//业务种类
			trxInf.setBizTp("100007");

			//订单信息
			NuccEbankBodyOrdrinf ordrInf = new NuccEbankBodyOrdrinf();
			//订单编码
			ordrInf.setOrdrId(base.getOrderId());
			//订单详情
			ordrInf.setOrdrDesc(orderDescSb.toString());
			//回跳地址
			ordrInf.setClbckUrl(nuccConfig.get("NUCC.GWB2C.BACK.URL"));

			body.setGwChnnlTp(NuccConstants.NUCC_GW_CHNNL_TP_01);//网关支付受理渠道
			body.setRrxDevcInf(base.getSpecial3()+"|||||||");//交易设备信息

			body.setPyerInf(pyerInf);
			body.setPyeeInf(pyeeInf);
			body.setResfdInf(resfdInf);
			body.setTrxInf(trxInf);
			body.setOrdrInf(ordrInf);
			message.setMsgHeader(header);
			message.setMsgBody(body);
			message.setCustomerID(null);
		}catch(Exception e){
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6129,e);
		}
		return message;

	}

	private String amountFormat(String amount){
		DecimalFormat df = new DecimalFormat("0.00");
		return  df.format(new BigDecimal(amount));
	}

	public Object queryOrder(BaseMessage base) throws GopayException {
		NuccBaseMessage message = this.buildQueryOrder(base);
		logger.info(" nucc manager b2c query send message: " + ToStringBuilder.reflectionToString(message));
		NuccQueryRes res = (NuccQueryRes) nuccCommonServiceClient.queryTransStatus(message);
		res.setOutStlmCd(BankConstants.BANK_LOGO_NUCCPAY);
		logger.info(" nucc manager b2c query return message: " + ToStringBuilder.reflectionToString(message));
		return res;
	}

	/**
	 * 构建订单查询请求报文
	 * @param base
	 * @return
	 * @author zhoutong
	 */
	public NuccBaseMessage buildQueryOrder(BaseMessage base){
		NuccBaseMessage message = new NuccBaseMessage();
		BeanUtils.copyProperties(base, message);
		NuccBaseHeaderMessage header = new NuccBaseHeaderMessage();
		NuccQueryBodyReq body = new NuccQueryBodyReq();

		CpsGenMainOrder mainOrder = mainOrderQuery.get(base.getOrderId());
		BankOrder bankOrder =bankOrderManager.getBankOrderById(base.getBankOrderId());
		header.setSndDt(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
		//报文类型代码
		header.setMsgTp(nuccConfig.get("NUCC.QUERY.MSGTP"));
		//发起方所属机构标示
		header.setIssrId(nuccConfig.get("GOPAY.ISSRID"));
		//报文方向  11-支付机构到平台
		header.setDrctn(nuccConfig.get("NUCC.DRCTN.TONUCC"));
		//签名证书序列号
		header.setSignSN(nuccConfig.get("NUCC.QUERY.SIGNSN"));

		NuccQueryBodyOriTrxinf oriTrxInf = new NuccQueryBodyOriTrxinf();

		if(BisBankBusinessProd._12.value.equals(bankOrder.getBankBizProdCode())){
			//退款交易类别
			oriTrxInf.setOriTrxCtgy(nuccConfig.get("NUCC.GW.REFUND.TRXCTGY"));
		}else{
			//支付交易类别
			oriTrxInf.setOriTrxCtgy(nuccConfig.get("NUCC.GW.PAY.TRXCTGY"));
		}
		oriTrxInf.setOriTrxId(base.getBankOrderId());
		oriTrxInf.setOriTrxDtTm(DateUtils.format(mainOrder.getCreatedTs(), "yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
		body.setOriTrxInf(oriTrxInf);
		body.setInstgId(nuccConfig.get("GOPAY.ISSRID"));
		//设置支付地址
		String bankOrderId=base.getBankOrderId();
		String ip =bankOrderId.substring(bankOrderId.length()-6, bankOrderId.length()-4) ;
		message.setPayUrl(nuccSerialManager.getUrlBySerial(ip));
		message.setMsgHeader(header);
		message.setMsgBody(body);
		return message;

	}



	@Override
	public Object verify(BaseMessage base) throws GopayException {
		NuccEbankEndRes message = new NuccEbankEndRes();
		BeanUtils.copyProperties(base, message);
		logger.info("nucc b2c manager veirfy message before: " + ToStringBuilder.reflectionToString(message));
		message = (NuccEbankEndRes) nuccGwServiceClient.verify(message);
		logger.info("nucc b2c manager veirfy message after: " + ToStringBuilder.reflectionToString(message));
		return message;
	}

	@Override
	public Object query(Object obj) throws GopayException {
		return null;
	}

	/**
	 * 网联退款
	 * @param base
	 * @return
	 * @throws GopayException
	 */
	@Override
	public Object refund(BaseMessage base) throws GopayException {
		NuccBaseMessage message = this.buildRefund(base);
		logger.info("nucc b2 manager refund send message: " + ToStringBuilder.reflectionToString(message));
		NuccRefundRes res = (NuccRefundRes) nuccCommonServiceClient.refund(message);
		res.setOutStlmCd(BankConstants.BANK_LOGO_NUCCPAY);
		logger.info("nucc b2c manager refund return message: " + ToStringBuilder.reflectionToString(message));
		return res;
	}

	/**
	 * 构建退款请求报文
	 * @param base
	 * @return
	 * @author 周通
	 */
	public NuccBaseMessage buildRefund(BaseMessage base)throws GopayException {
		NuccBaseMessage message = new NuccBaseMessage();
		BeanUtils.copyProperties(base, message);
		NuccBaseHeaderMessage header = new NuccBaseHeaderMessage();
		NuccRefundBodyReq body = new NuccRefundBodyReq();
		try{
			header.setSndDt(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
			//报文类型代码
			header.setMsgTp(nuccConfig.get("NUCC.REFUND.MSGTP"));
			//发起方所属机构标示
			header.setIssrId(nuccConfig.get("GOPAY.ISSRID"));
			//报文方向  11-支付机构到平台
			header.setDrctn(nuccConfig.get("NUCC.DRCTN.TONUCC"));
			//签名证书序列号
			header.setSignSN(nuccConfig.get("NUCC.REFUND.SIGNSN"));

			//退款方信息
			NuccRefundBodyPyerinf pyerInf = new NuccRefundBodyPyerinf();
			//退款方账户所属机构标示
			pyerInf.setPyerAcctIssrId(nuccConfig.get("GOPAY.ISSRID"));
			//退款方账户(付款方的支付账户编号)
			CpsGenMainOrder mainOrder = mainOrderQuery.get(base.getTkOriOrderId());
			pyerInf.setPyerAcctId(mainOrder.getMainRecvAcct());
			//退款方账户类型
			pyerInf.setPyerAcctTp("04");

			//收款方信息
			NuccRefundBodyPyeeinf pyeeInf = new NuccRefundBodyPyeeinf();
			BankOrder oriBankOrder = bankOrderManager.getBankOrderById(base.getTkOriBankOrderId());
			//收款方账户所属机构标示
			pyeeInf.setPyeeAcctIssrId(BankOfAffiliationConstants.getAffiliation(oriBankOrder.getBankCode()));
			pyeeInf.setPyeeAcctTp("99");
			//备付金信息
			NuccRefundBodyResfdinf resfdInf = new NuccRefundBodyResfdinf();
			String[] aInfo = nuccSerialManager.getAccountInfo(oriBankOrder.getBankCode());
			//支付机构备付金账户
			resfdInf.setInstgAcctId(aInfo[0]);
			//备付金账户所属机构标示
			resfdInf.setResfdAcctIssrId(aInfo[1]);
			
	/*		//支付机构备付金账户
			resfdInf.setInstgAcctId(nuccConfig.get("NUCC.REFUND.GOPAY.INSTG.ACCT.ID"));
			//备付金账户所属机构标示
			resfdInf.setResfdAcctIssrId(nuccConfig.get("NUCC.REFUND.GOPAY.RESFD.ACCT.ISSRID"));
*/
			//交易信息
			NuccRefundBodyTrxinf trxInf = new NuccRefundBodyTrxinf();
			//交易类别
			trxInf.setTrxCtgy(nuccConfig.get("NUCC.GW.REFUND.TRXCTGY"));
			//交易流水号
			String bankOrderId = base.getBankOrderId();
			trxInf.setTrxId(bankOrderId);
			String ip =bankOrderId.substring(bankOrderId.length()-6, bankOrderId.length()-4) ;
			message.setPayUrl(nuccSerialManager.getUrlBySerial(ip));
			//交易日期时间
			trxInf.setTrxDtTm(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
			//交易金额
			String amount = "CNY"+amountFormat(base.getAmount().toString());
			trxInf.setTrxAmt(amount);

			//原交易信息
			NuccRefundBodyOriTrxinf oriTrxInf = new NuccRefundBodyOriTrxinf();
			//原支付交易流水号
			oriTrxInf.setOriTrxId(base.getTkOriBankOrderId());
			//原付款银行流水号
			oriTrxInf.setOriDbtrBankId(oriBankOrder.getBankOrderId());
			oriTrxInf.setOriTrxAmt("CNY"+amountFormat(oriBankOrder.getSendBankAmt().toString()));

			body.setPyerInf(pyerInf);
			body.setPyeeInf(pyeeInf);
			body.setResfdInf(resfdInf);
			body.setTrxInf(trxInf);
			body.setOriTrxInf(oriTrxInf);
			message.setMsgHeader(header);
			message.setMsgBody(body);
		}catch(Exception e){
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6133,e);
		}
		return message;

	}

	@Override
	public Object dayend(BaseMessage base) throws GopayException, Exception {
		return null;
	}

	public Map<String, String> getNuccConfig() {
		return nuccConfig;
	}

	public void setNuccConfig(Map<String, String> nuccConfig) {
		this.nuccConfig = nuccConfig;
	}

	public NuccSerialManager getNuccSerialManager() {
		return nuccSerialManager;
	}

	public void setNuccSerialManager(NuccSerialManager nuccSerialManager) {
		this.nuccSerialManager = nuccSerialManager;
	}

	public NuccEbankService getNuccGwServiceClient() {
		return nuccGwServiceClient;
	}

	public void setNuccGwServiceClient(NuccEbankService nuccGwServiceClient) {
		this.nuccGwServiceClient = nuccGwServiceClient;
	}

	public NuccCommonService getNuccCommonServiceClient() {
		return nuccCommonServiceClient;
	}

	public void setNuccCommonServiceClient(NuccCommonService nuccCommonServiceClient) {
		this.nuccCommonServiceClient = nuccCommonServiceClient;
	}

	public BankOrderManager getBankOrderManager() {
		return bankOrderManager;
	}

	public void setBankOrderManager(BankOrderManager bankOrderManager) {
		this.bankOrderManager = bankOrderManager;
	}

	public CpsGeneralMainOrderQueryManager getMainOrderQuery() {
		return mainOrderQuery;
	}

	public void setMainOrderQuery(CpsGeneralMainOrderQueryManager mainOrderQuery) {
		this.mainOrderQuery = mainOrderQuery;
	}

	public CustCorpInfoDao getCustCorpInfoDao() {
		return custCorpInfoDao;
	}

	public void setCustCorpInfoDao(CustCorpInfoDao custCorpInfoDao) {
		this.custCorpInfoDao = custCorpInfoDao;
	}

	public PgGeneralOrderTransDtlDAO getCommonPgGeneralOrderTransDtlDAO() {
		return commonPgGeneralOrderTransDtlDAO;
	}

	public void setCommonPgGeneralOrderTransDtlDAO(PgGeneralOrderTransDtlDAO commonPgGeneralOrderTransDtlDAO) {
		this.commonPgGeneralOrderTransDtlDAO = commonPgGeneralOrderTransDtlDAO;
	}
}
